package timing.ukulele.auth.security.handler;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import timing.ukulele.auth.config.properties.TimingSecurityProperties;
import timing.ukulele.auth.security.user.BaseUserDetail;
import timing.ukulele.auth.support.RedisOperator;
import timing.ukulele.auth.util.JsonUtils;
import timing.ukulele.common.data.ResponseData;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static timing.ukulele.share.Constant.*;

/**
 * 登录成功处理类
 */
@Slf4j
public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    private final JwtEncoder encoder;
    private final TimingSecurityProperties securityProperties;

    private final RedisOperator<String> redisOperator;

    public LoginSuccessHandler(
            RedisOperator<String> redisOperator, JwtEncoder encoder, TimingSecurityProperties securityProperties) {
        this.redisOperator = redisOperator;
        this.encoder = encoder;
        this.securityProperties = securityProperties;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        log.debug("登录成功.");
        ResponseData<String> success = ResponseData.success();
        Instant now = Instant.now();
        long expiry = 36000L;
        List<String> scopes = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList());
        BaseUserDetail userInfo = (BaseUserDetail) authentication.getPrincipal();
        // 生成一个随机字符串，将用户信息保存至redis
        String key = UUID.randomUUID().toString();
        String cachekey = TOKEN_CACHE_PREFIX + key;
        redisOperator.set(cachekey, JsonUtils.objectCovertToJson(userInfo), expiry, TimeUnit.SECONDS);
        JwtClaimsSet claims = JwtClaimsSet.builder()
                .issuer(securityProperties.getIssuerUrl())
                .issuedAt(now)
                .expiresAt(now.plusSeconds(expiry))
                .subject(key)
                .claim(SCOPES_KEY, scopes)
                .claim(AUTHORITIES_KEY, authentication.getAuthorities())
                .build();
        String tokenValue = encoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
        success.setData(tokenValue);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.getWriter().write(JsonUtils.objectCovertToJson(success));
        response.getWriter().flush();
    }

}
